#线程池i/o密集型
import requests
from lxml import etree
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
import time
# 爬虫函数
def craw(start):
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0'
    }
    url = 'https://yz.chsi.com.cn/sch/search.do'
    params = {
        'start': start
    }
    response = requests.get(url=url, params=params, headers=headers)
    response.raise_for_status()  # 检查请求是否成功
    return response.text

# 数据解析函数
def parse(html):
    tree = etree.HTML(html)
    div_list = tree.xpath('//div[@class="sch-list-container"]/div')
    schools = []
    for div in div_list:
        name_data = div.xpath('.//a[@class="name js-yxk-yxmc text-decoration-none"]/text()')[0]
        name_data = name_data.strip()
        href_data = 'https://yz.chsi.com.cn' + \
                     div.xpath('.//a[@class="name js-yxk-yxmc text-decoration-none"]/@href')[0]
        schools.append((name_data, href_data))
    return schools
# 主函数

def multi_process():
    # map函数的第二个参数是参数列表而不是一个参数
    page_starts = [i * 20 for i in range(40)]
    start = time.time()
    # 使用第一个线程池进行页面爬取
    with ProcessPoolExecutor() as craw_pool:
        html_pages = list(
            craw_pool.map(craw, page_starts))  # 获取结果列表爬取的网页入参顺序一一对应第一个start对应第一个html,把pool返回的迭代器转换为一个列表方便后续处理
    # html_pages是一个列表，它包含了从 中的每个起始位置爬取到的 HTML 页面内容。列表中的每个元素都是一个字符串，代表一个网页的 HTML 内容
    # 使用第二个线程池进行页面解析
    with ProcessPoolExecutor() as parse_pool:
        futures_parse = [parse_pool.submit(parse, html) for html in html_pages]  # 把列表的html进行遍历,把返回的future对象放入futures列表中

        # 使用result函数用来解析future对象的 等待所有解析任务完成，并收集结果
        schools_list = [future.result() for future in futures_parse]
    # 使用chain.from_iterable来合并所有的学校列表
    all_schools = [school for schools in schools_list for school in
                   schools]  # 从schools_list列表中遍历得到每个schools(列表)在把每一个schools遍历的到school(schools是一个列表存放了每个学校的(name,url)(元组)
    end = time.time()
    # 打印所有学校的名称和URL(遍历一个包含元组的列表)
    for school_name, school_url in all_schools:
        print(f"{school_name}, {school_url}")
    print("multi_process cost", end - start)

# 运行主函数
if __name__ == "__main__":

    multi_process()


